import { _decorator, director, Animation, resources, SpriteFrame, Color, ProgressBar, JsonAsset, AudioClip, AudioSource, BoxCollider2D, Collider2D, Component, Contact2DType, find, instantiate, IPhysics2DContact, Label, Node, PolygonCollider2D, Prefab, RigidBody2D, Sprite, tween, UITransform, Vec3 } from 'cc';
const { ccclass, property } = _decorator;
import { PixelItem } from './PixelItem';
import { ColorBoard } from './ColorBoard';
import { Monster } from './Monster';
import { EquipmentBpBox } from './EquipmentBpBox';
import { Intro } from './Intro';
import { Utils } from './Utils';
import { Boss } from './Boss';
import { Wand } from './Wand';

@ccclass('Player')
export class Player extends Component {
    @property({type: JsonAsset})
    equipmentJsonAsset: JsonAsset = null!


    @property({type: Node})
    HPProgressBarNode: Node = null!

    @property({type: Node})
    HPValueNode: Node = null!

    @property({type: Node})
    stateNode: Node = null!

    @property({type: Node})
    weaponNode: Node = null!

    @property({type: Prefab})
    lightBeamPrefab: Prefab = null!

    @property({type: Prefab})
    fireballPrefab: Prefab = null!

    @property({type: Prefab})
    lightningPrefab: Prefab = null!

    @property({type: Prefab})
    trashBinPrefab: Prefab = null!

    @property({type: Prefab})
    addInfoPrefab: Prefab = null!

    @property({type: Prefab})
    damagePrefab: Prefab = null

    @property({type: AudioClip})
    blinkAudio: AudioClip = null!

    @property({type: AudioClip})
    moveAudio: AudioClip = null!

    @property({type: AudioClip})
    eatAudio: AudioClip = null!

    @property({type: AudioClip})
    stickAudio: AudioClip = null!

    @property({type: AudioClip})
    hitPlayerAudio: AudioClip = null!

    @property({type: AudioClip})
    dieAudio: AudioClip = null!

    @property({type: AudioClip})
    recoverAudio: AudioClip = null!

    @property({type: AudioClip})
    dashAudio: AudioClip = null!

    @property({type: AudioClip})
    lightBeamAudio: AudioClip = null!

    @property({type: AudioClip})
    fireballAudio: AudioClip = null!

    @property({type: AudioClip})
    lightningAudio: AudioClip = null!

    @property({type: AudioClip})
    mouseClickAudio: AudioClip = null!

    isInvincible: boolean = false
    xDir: number = 1                                                                // X轴方向
    yDir: number = 1                                                                // Y轴方向
    speed: number = 5                                                               // 移动速度
    life: number = 100                                                              // 主角血量
    defense: number = 1                                                             // 防御力
    isDead: boolean = false                                                         // 是否死亡
    isMoving: boolean = false                                                       // 是否移动
    isAttacking: boolean = false                                                    // 是否正在攻击
    restrictAreaNode: Node = null!                                                  // 限制区域
    weaponInfo: object = null                                                       // 武器信息
    equipmentJsonData: object = null

    utils: Utils = null!
    audioSource: AudioSource = null!                                                
    playerAnimationComp: Animation = new Animation()
    playerUITransform: UITransform = new UITransform()                              
    restrictAreaUITransform: UITransform = new UITransform()

    start() {
        this.equipmentJsonData = this.equipmentJsonAsset.json
        this.blinkRandomly()
        this.initComponents()
        this.initColliderEvents()
        this.initPlayerProperties()
        this.showPlayerEquipments()
        this.setRestrictArea(find('Canvas'))
    }

    /** 
     * @zh
     * 根据缓存数据显示主角装备。
    */
    showPlayerEquipments () {
        // 获取武器信息
        if (localStorage.getItem('lp-weapon')) {
            let weaponName = localStorage.getItem('lp-weapon')
            if (weaponName.indexOf('custom') == -1) {
                resources.load(`equipment/${weaponName}/spriteFrame`, SpriteFrame, (err: any, spriteFrame: SpriteFrame) => {
                    this.weaponNode.getComponent(Sprite).spriteFrame = spriteFrame
                    this.weaponInfo = this.equipmentJsonData[weaponName]
                })
            }
            else {
                let points = JSON.parse(weaponName.split('-')[2])
                let customWeaponNode = this.weaponNode.children[0]
                for (let i=0; i<points.length; i++) {
                    let index = points[i][0]
                    let colorHex = points[i][1]
                    customWeaponNode.children[index].getComponent(Sprite).color = new Color().fromHEX(colorHex)
                }
                this.weaponInfo = this.equipmentJsonData['customWeapon']
                this.weaponInfo['damage'] = weaponName.split('-')[1]
            }
        }

        // 获取帽子防具信息
        if (localStorage.getItem('lp-hat')) {
            let hatName = localStorage.getItem('lp-hat')
            resources.load(`equipment/${hatName}/spriteFrame`, SpriteFrame, (err: any, spriteFrame: SpriteFrame) => {
                this.node.getChildByName('Hat').getComponent(Sprite).spriteFrame = spriteFrame
                this.defense += this.equipmentJsonData[hatName]['defense']
            })
        }
    }

    /** 
     * @zh
     * 初始化组件。
    */
    initComponents() {
        this.utils = find('Canvas').getComponent(Utils)
        this.audioSource = find('Canvas').getComponent(AudioSource)
        this.playerAnimationComp = this.node.getComponent(Animation)
        this.playerUITransform = this.node.getComponent(UITransform)
    }

    /** 
     * @zh
     * 初始化碰撞组件。
    */
    initColliderEvents() {
        let playerCollider = this.node.getComponent(BoxCollider2D)
        let weaponCollider = this.weaponNode.getComponent(PolygonCollider2D)
        playerCollider.on(Contact2DType.BEGIN_CONTACT, this.onPlayerBeginContact, this)
        weaponCollider.on(Contact2DType.BEGIN_CONTACT, this.onWeaponBeginContact, this)
    }

    /** 
     * @zh
     * 主角属性。
    */
    initPlayerProperties() {
        this.setLifeProgressBar()
    }

    /** 
     * @zh
     * 主角碰撞时执行的逻辑。
    */
    onPlayerBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact|null) {
        // 碰到颜料
        if (otherCollider.node.name.indexOf('pixelItem') > -1) {
            // 移除像素块
            otherCollider.enabled = false
            otherCollider.node.removeFromParent()
            this.audioSource.playOneShot(this.eatAudio, 0.5)

            // 显示数量添加动画
            let addInfoNode = instantiate(this.addInfoPrefab)
            let pixelColor = otherCollider.node.getComponent(Sprite).color
            let pixelNum = otherCollider.node.getComponent(PixelItem).pixelNum
            addInfoNode.children[0].getComponent(Sprite).color = pixelColor
            addInfoNode.children[1].getComponent(Label).string = `+${pixelNum}`  // 节点名称示例：pixelItem-10
            addInfoNode.setPosition(otherCollider.node.position)
            find('Canvas').addChild(addInfoNode)
            tween(addInfoNode).by(0.8, {'position': new Vec3(0, 60, 0)}, {'easing': 'sineOut'})
                              .call(()=>{addInfoNode.removeFromParent()})
                              .start()
            
            // 更新颜料面板上的数量
            find('Canvas/Color Board ScrollView').getComponent(ColorBoard).updateColorData(pixelColor.toHEX(), pixelNum)
        }

        // 碰到制作图
        else if (otherCollider.node.name.indexOf('equipment') > -1) {{
            let addInfoNode = instantiate(this.addInfoPrefab)
            addInfoNode.children[0].getComponent(Sprite).spriteFrame = otherCollider.node.children[0].getComponent(Sprite).spriteFrame
            addInfoNode.children[1].getComponent(Label).string = `+1`
            addInfoNode.setPosition(otherCollider.node.position)
            find('Canvas').addChild(addInfoNode)
            tween(addInfoNode).by(0.8, {'position': new Vec3(0, 60, 0)}, {'easing': 'sineOut'})
                              .call(()=>{addInfoNode.removeFromParent()})
                              .start()

            // 缓存中加入吃到的制作图
            let itemKey = otherCollider.node.name.split('-')[1]
            console.log('吃到制作图', itemKey)
            find('Canvas/Blueprint Background/Equipment BP Box').getComponent(EquipmentBpBox).updateEquipmentBpBoxInfo('ADD', itemKey, 1, this.equipmentJsonData[itemKey])            
        
            otherCollider.node.removeFromParent()
            this.audioSource.playOneShot(this.eatAudio, 0.5)
        }}

        // 碰到怪物
        else if (otherCollider.node.name == 'monster') {
            if (this.isDead) {
                return
            }
            
            // 无敌状态下无法被伤害，且怪物后退
            if (this.isInvincible) {
                otherCollider.node.getComponent(Monster).stepBack()
                return
            }
            
            let damageValueFromMonster = Math.round(Math.random() * otherCollider.node.getComponent(Monster).monsterInfo['damage'])
            this.reduceLife(damageValueFromMonster, otherCollider.node)
        }

        // 碰到怪物
        else if (otherCollider.node.name == 'Boss') {
            if (this.isDead) {
                return
            }
            
            // 无敌状态下无法被伤害，且怪物后退
            if (this.isInvincible) {
                otherCollider.node.getComponent(Boss).stepBack()
                return
            }
            
            let damageValueFromMonster = Math.round(Math.random() * otherCollider.node.getComponent(Boss).damage)
            this.reduceLife(damageValueFromMonster, otherCollider.node)
        }
    }

    /** 
     * @zh
     * 武器碰撞时执行的逻辑。
    */
    onWeaponBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact|null) {        
        // 只有在攻击状态下武器才能和怪物发生碰撞（不然怪物就直接自己碰到武器了）
        if (otherCollider.node.name == 'monster' && this.isAttacking) {
            if (!this.weaponInfo) {
                // 身体撞击
                let damageValue = Math.round(Math.random() * 10 + 100 / 10)        // 没有武器的话基础攻击力为10
                otherCollider.node.getComponent(Monster).reduceLife(damageValue)
                return
            }

            // 怪物血量减少
            let damageValue = Math.round(Math.random() * this.weaponInfo['damage'] + this.weaponInfo['damage'] / 10)
            otherCollider.node.getComponent(Monster).reduceLife(damageValue)
        }
        else if (otherCollider.node.name == 'Boss' && this.isAttacking) {
            if (!this.weaponInfo) {
                // 身体撞击
                let damageValue = Math.round(Math.random() * 10 + 10)           // 没有武器的话基础攻击力为10
                otherCollider.node.getComponent(Boss).reduceLife(damageValue)
                return
            }

            // 怪物血量减少
            let damageValue = Math.round(Math.random() * this.weaponInfo['damage'] + this.weaponInfo['damage'] / 10)
            otherCollider.node.getComponent(Boss).reduceLife(damageValue)
        }
    }

    /** 
     * @zh
     * 模拟随机眨眼。
    */
    blinkRandomly() {
        this.schedule(()=>{
            let blinkTime = Math.random() * 5 + 5
            this.scheduleOnce(()=>{this.blink()}, blinkTime)
        }, 5)
    }

    /** 
     * @zh
     * 根据血量设置进度条。
    */
    setLifeProgressBar() {
        this.HPValueNode.getComponent(Label).string = `${this.life}/${this.life}`
        this.HPProgressBarNode.getComponent(UITransform).width = this.life
        this.HPProgressBarNode.getComponent(ProgressBar).totalLength = this.life
    }

    /** 
     * @zh
     * 人物眨眼。
    */
    blink() {
        if (this.isDead) {
            return
        }

        this.playerAnimationComp.play('blink')

        if (Math.random() > 0.5) {
            this.scheduleOnce(()=>{
                this.playerAnimationComp.play('blink')
            }, 0.1)
        }
    }

    /** 
     * @zh
     * 人物移动。
    */
    move() {
        let moveAnimationState = this.playerAnimationComp.getState('move')
        let attackAnimationState = this.playerAnimationComp.getState('attack')
        if (!moveAnimationState.isPlaying && !attackAnimationState.isPlaying) {
            this.playerAnimationComp.play('move')
        }
        this.node.setPosition(new Vec3(this.node.position).add(new Vec3(this.xDir*this.speed, this.yDir*this.speed, 0)))
    }

    /** 
     * @zh
     * 播放走路音效(动画编辑器中的回调)。
    */
    playMoveAudio() {
        this.audioSource.playOneShot(this.moveAudio, 0.2)
    }

    // /** 
    //  * @zh
    //  * 播放眨眼音效(动画编辑器中的回调)。
    // */
    // playBlinkAudio() {
    //     this.audioSource.playOneShot(this.blinkAudio, 0.2)
    // }

    /** 
     * @zh
     * 设置人物限制区域。
    */
    setRestrictArea(node: Node) {
        this.restrictAreaNode = node
        this.restrictAreaUITransform = this.restrictAreaNode.getComponent(UITransform)
    }

    /** 
     * @zh
     * 限制人物的位置。
    */
    limitPlayer() {
        let x = this.node.position.x
        let y = this.node.position.y

        if (x + this.playerUITransform.width/2 >= this.restrictAreaUITransform.width/2) {
            x = this.restrictAreaUITransform.width/2 - this.playerUITransform.width/2
        }
        else if (x - this.playerUITransform.width/2 <= -this.restrictAreaUITransform.width/2) {
            x = -this.restrictAreaUITransform.width/2 + this.playerUITransform.width/2, y, 0
        }
        if (y + this.playerUITransform.height/2 >= this.restrictAreaUITransform.height/2) {
            y = this.restrictAreaUITransform.height/2 - this.playerUITransform.height/2
        }
        else if (y - this.playerUITransform.height/2 <= -this.restrictAreaUITransform.height/2) {
            y = -this.restrictAreaUITransform.height/2 + this.playerUITransform.height/2
        }

        this.node.setPosition(x, y, 0)
    }

    /** 
     * @zh
     * 攻击，播放武器挥动缓动。
    */
    attack() {
        // 正在攻击 或者 没有武器装备的话直接返回
        if (this.isDead || this.isAttacking) {
            return
        }

        this.isAttacking = true
        // 如果没有武器的话则播放撞击动画
        if (!this.weaponInfo) {
            this.playerAnimationComp.stop()
            this.playerAnimationComp.play('attack')
            this.audioSource.playOneShot(this.dashAudio)
            tween(this.node).by(0.3, {'position': new Vec3(this.node.scale.x*100, 0, 0)}, {'easing': 'sineInOut'})
                            .call(()=>{this.isAttacking=false})
                            .start()
            return
        }

        // 魔杖发射魔法球
        if (this.weaponInfo['en'] == 'wand') {
            this.weaponNode.getComponent(Wand).shoot()
        }

        // 武器挥砍缓动
        let rotateForward = tween(this.weaponNode).by(0.1, {'angle': -50}, {'easing': 'sineOut'})
        let moveForward = tween(this.weaponNode).by(0.1, {'position': new Vec3(20, -10, 0)}, {'easing': 'sineOut'})
        let rotateBack = tween(this.weaponNode).by(0.1, {'angle': 50}, {'easing': 'sineInOut'})
        let moveBack = tween(this.weaponNode).by(0.1, {'position': new Vec3(-20, 10, 0)}, {'easing': 'sineInOut'})
        let para1 = tween(this.weaponNode).parallel(rotateForward, moveForward).call(()=>{this.audioSource.playOneShot(this.stickAudio)})
        let para2 = tween(this.weaponNode).parallel(rotateBack, moveBack)
        tween(this.weaponNode).sequence(para1, para2)
                              .call(()=>{this.isAttacking = false})
                              .start()
    }
    
    /** 
     * @zh
     * 降低生命值。
    */
    reduceLife(damageValueFromOtherNode: number, otherNode: Node) {
        if (damageValueFromOtherNode - this.defense <= 0) {
            // Miss
            this.showDamageValue(0)

            // 碰撞事件没有STAY_CONTACT了
            // Miss的时候会出现一种情况：碰撞已结束不再触发，如果主角此时不动，那怪物和主角互相伤害不到，这就是一个非常和谐的场面。
            // 怪物和主角靠的近的时候是需要反应的，所以这里如果出现Miss的话过0.5秒后再判断两者距离看下是否需要扣血
            let callback = ()=> {
                if (new Vec3(this.node.position).subtract(otherNode.position).length() < otherNode.getComponent(UITransform).width/1.2) {
                    if (otherNode.name == 'Boss') {
                        damageValueFromOtherNode = Math.round(Math.random() * otherNode.getComponent(Boss).damage + otherNode.getComponent(Boss).damage/2)
                    }
                    else {
                        damageValueFromOtherNode = Math.round(Math.random() * otherNode.getComponent(Monster).monsterInfo['damage'] + otherNode.getComponent(Monster).monsterInfo['damage']/2)
                    }
                    this.reduceLife(damageValueFromOtherNode, otherNode)
                }
            }
            this.scheduleOnce(callback, 0.5)
        }
        else {
            this.updatePlayerStateWhenGetHurt(damageValueFromOtherNode, otherNode)
        }
    }

    /** 
     * @zh
     * 主角受伤时更新主角状态。
    */
    updatePlayerStateWhenGetHurt(damageValueFromMonster: number, monsterNode: Node) {
        if (this.isDead) {
            return
        }

        let totalLength = this.HPProgressBarNode.getComponent(ProgressBar).totalLength
        let realDamage = damageValueFromMonster - this.defense
        totalLength -= realDamage
        if (totalLength <= 0) {
            totalLength = 0
            this.showDamageValue(realDamage)
            this.die()
        }
        else {
            this.flash()
            this.stepBack(monsterNode.position)
            this.showDamageValue(realDamage)
        }

        this.HPProgressBarNode.getComponent(ProgressBar).totalLength = totalLength
        this.HPValueNode.getComponent(Label).string = `${this.life}/${totalLength.toString()}`
        this.audioSource.playOneShot(this.hitPlayerAudio)
    }
    
    /** 
     * @zh
     * 被攻击时后退。
    */
    stepBack(monsterPos: Vec3) {
        // 冲撞情况下，碰到怪物不后退
        if (this.isAttacking && !this.weaponInfo) {
            return
        }

        let dir = new Vec3(this.node.position).subtract(monsterPos).normalize()
        tween(this.node).by(0.1, {'position': new Vec3(80*dir.x, 80*dir.y, 0)}, {'easing': 'sineInOut'}).start()
    }
    
    /** 
     * @zh
     * 闪白（主角本身是白的，闪白效果就用透明来代替了）。
    */
    flash() {
        this.isInvincible = true
        this.stateNode.active = true    // 显示无敌字样
        this.stateNode.getComponent(Label).string = '无敌状态'

        let count = 0
        let callback = () => {
            let color = this.node.getComponent(Sprite).color
            if (color.a != 255) {
                this.node.getComponent(Sprite).color = new Color(color.r, color.g, color.b, 255)
            }
            else {
                this.node.getComponent(Sprite).color = new Color(color.r, color.g, color.b, 180)
            }

            count += 1
            if (count == 15) {
                this.unschedule(callback)
                this.isInvincible = false
                this.stateNode.active = false
                this.node.getComponent(Sprite).color = new Color(color.r, color.g, color.b, 255) // 确保颜色不透明
            }
        }
        this.schedule(callback, 0.1)
    }

    /** 
     * @zh
     * 显示伤害值。
    */
    showDamageValue(damageValue: number) {
        let damageNode = instantiate(this.damagePrefab)
        if (damageValue <= 0) {
            damageNode.getComponent(Label).string = 'Miss'
        }
        else {
            damageNode.getComponent(Label).string = `-${damageValue}`
            damageNode.getComponent(Label).color = new Color(230, 0, 0)
        }

        damageNode.setPosition(this.node.position)
        find('Canvas').addChild(damageNode)
        tween(damageNode).by(0.8, {'position': new Vec3(0, 60, 0)}, {'easing': 'sineOut'})
                         .call(()=>{damageNode.removeFromParent()})
                         .start()
    }

    /** 
     * @zh
     * 主角失败。
    */
    die() {
        this.isDead = true
        this.audioSource.playOneShot(this.dieAudio)
        this.HPProgressBarNode.getComponent(ProgressBar).totalLength = 0
        this.HPValueNode.getComponent(Label).string = `${this.life}/0`
        this.playerAnimationComp.play('die')

        // 死亡的话装备消失，同时删除对应的缓存
        this.weaponInfo = null
        this.weaponNode.getComponent(Sprite).spriteFrame = null
        let customWeaponNode = this.weaponNode.children[0]
        for (let i =0; i<customWeaponNode.children.length; i++) {
            customWeaponNode.children[i].getComponent(Sprite).color = new Color(0, 0, 0, 0)
        }
        localStorage.removeItem('lp-weapon')
        this.node.getChildByName('Hat').getComponent(Sprite).spriteFrame = null
        localStorage.removeItem('lp-hat')
        this.defense = 1    // 没帽子，防御力重置

        // 如果不是引导阶段，则判断背包里有没有药，没有药的话欢迎下一位勇士
        if (!find('Canvas').getComponent(Intro).enabled) {
            if (localStorage.getItem('lp-backpack') && 'cure' in JSON.parse(localStorage.getItem('lp-backpack'))) {
                this.utils.showFlashMessage('使用背包中的治疗药水，然后继续战斗!', 10)
            }
            else {
                this.utils.showFlashMessage('背包中没有治疗药水\n等待下一位勇士到来', 5)
                this.updateDeadPlayerNum()
    
                // 所有物品消失
                localStorage.removeItem('lp-backpack')
                localStorage.removeItem('lp-color-data')
                localStorage.removeItem('lp-equipment-bp-box')
                
                this.scheduleOnce(()=>{
                    director.loadScene('game')
                }, 5)
            }
        }
    }

    /** 
     * @zh
     * 失败时，记录死亡的勇士数量。
    */
    updateDeadPlayerNum() {
        if (!localStorage.getItem('lp-player-num')) {
            localStorage.setItem('lp-player-num', '0')
        }
        let deadPlayerNum = parseInt(localStorage.getItem('lp-player-num')) + 1
        localStorage.setItem('lp-player-num', deadPlayerNum.toString())
    }

    /** 
     * @zh
     * 恢复血量。
    */
    recoverLife(value: number) {
        let totalLength = this.HPProgressBarNode.getComponent(ProgressBar).totalLength
        totalLength += value
        if (totalLength >= this.life) {
            totalLength = this.life
        }
        
        this.flash()
        this.HPProgressBarNode.getComponent(ProgressBar).totalLength = totalLength
        this.HPValueNode.getComponent(Label).string = `${this.life}/${totalLength}`
        this.audioSource.playOneShot(this.recoverAudio)
        this.playerAnimationComp.play('blink')

        if (this.isDead) {
            this.isDead = false
            this.weaponNode.active = true
        }
    }
    
    /** 
     * @zh
     * 释放闪电暴击。
    */
    showLightningAttack() {
        let attachNum = Math.floor(Math.random()*20) + 20
        this.schedule(this.lightningAttack, 0.2, attachNum)
    }

    /** 
     * @zh
     * 闪电暴击逻辑。
    */
    lightningAttack() {
        let canvasNode = find('Canvas')
        let lightning = instantiate(this.lightningPrefab)

        let canvasWidth = canvasNode.getComponent(UITransform).width
        let canvasHeight = canvasNode.getComponent(UITransform).height
        let x = Math.random() * canvasWidth - canvasWidth/2
        let y = canvasHeight/2
        lightning.setPosition(x, y, 0)
        canvasNode.addChild(lightning)
        this.scheduleOnce(()=>{lightning.removeFromParent()}, 0.5)

        let damage = Math.round(Math.random() * 120 + 100)
        for (let i=0; i<canvasNode.children.length; i++) {
            let item = canvasNode.children[i]
            if (item.name == 'monster' && !item.getComponent(Monster).isDead && item.getComponent(UITransform).getBoundingBox().intersects(lightning.getComponent(UITransform).getBoundingBox())) {
                item.getComponent(Monster).reduceLife(damage)
            }
            else if (item.name == 'Boss' && item.active && !item.getComponent(Boss).isDead && item.getComponent(UITransform).getBoundingBox().intersects(lightning.getComponent(UITransform).getBoundingBox())) {
                item.getComponent(Boss).reduceLife(damage)
            }
        }
        this.audioSource.playOneShot(this.lightningAudio, 0.8)
    }

    /** 
     * @zh
     * 释放火球术。
    */
    showFireballAttack() {
        let attachNum = Math.floor(Math.random()*20) + 20
        this.schedule(this.fireballAttack, 0.2, attachNum)
    }

    /**
     * @zh
     * 火球术逻辑。
    */
    fireballAttack() {
        let fireball = instantiate(this.fireballPrefab)
        find('Canvas').addChild(fireball)
        this.audioSource.playOneShot(this.fireballAudio, 0.8)
    }

    /** 
     * @zh
     * 释放魔法光束。
    */
    showLightBeamAttack() {
        let attachNum = Math.floor(Math.random()*20) + 30
        this.schedule(this.lightBeamAttack, 0.2, attachNum)
    }

    /** 
     * @zh
     * 魔法光束逻辑。
    */
    lightBeamAttack() {
        let monsterArray = []
        let canvasNode = find('Canvas')
        for (let i=0; i<canvasNode.children.length; i++) {
            let item = canvasNode.children[i]
            if (item.name == 'monster' || item.name == 'Boss') {
                monsterArray.push(item)
            }
        }

        if (!monsterArray.length) {
            this.unschedule(this.lightBeamAttack)
            return
        }

        let targetNum = Math.floor(Math.random() * monsterArray.length)
        if (!monsterArray[targetNum] || !monsterArray[targetNum].active) {
            return
        }

        let lightBeam = instantiate(this.lightBeamPrefab)
        canvasNode.addChild(lightBeam)
        lightBeam.setSiblingIndex(10000)

        let rotation = Math.floor(Math.random()*360)
        lightBeam.setRotationFromEuler(0, 0, rotation)
        lightBeam.setPosition(monsterArray[targetNum].position)

        tween(lightBeam).to(0.2, {"scale": new Vec3(0.5, 3, 0)}, {"easing": "sineIn"})
                        .call(()=>{
                            lightBeam.removeFromParent()
                            
                            if (!monsterArray[targetNum]) {
                                return
                            }
                            
                            this.audioSource.playOneShot(this.lightBeamAudio, 0.8)
                            let damage = Math.round(Math.random() * 100 + 100)
                            if (monsterArray[targetNum].name == 'monster' && !monsterArray[targetNum].getComponent(Monster).isDead) {
                                monsterArray[targetNum].getComponent(Monster).reduceLife(damage)
                            }
                            else if (monsterArray[targetNum].name == 'Boss'&& !monsterArray[targetNum].getComponent(Boss).isDead) {
                                monsterArray[targetNum].getComponent(Boss).reduceLife(damage)
                            }
                        }).start()
    }

    /** 
     * @zh
     * 释放垃圾回收。
    */
    showTrashBinAttack() {
        let canvasNode = find('Canvas')
        let trashBin = instantiate(this.trashBinPrefab)
        canvasNode.addChild(trashBin)
        trashBin.setSiblingIndex(10000)

        // 动画帧事件不知道为什么播放不了这个音频，改用计时器延迟播放
        this.scheduleOnce(()=>{
            this.audioSource.playOneShot(this.mouseClickAudio, 2)
        }, 0.6)

        this.scheduleOnce(()=>{
            let damage = Math.round(Math.random() * 100 + 100)
            for (let i=0; i<canvasNode.children.length; i++) {
                let item = canvasNode.children[i]
                if (item.name == 'monster' && !item.getComponent(Monster).isDead) {
                    item.getComponent(Monster).reduceLife(damage)
                }
                else if (item.active && item.name == 'Boss' && !item.getComponent(Boss).isDead) {
                    item.getComponent(Boss).reduceLife(damage)
                }
            }
        }, 1.5)

        this.scheduleOnce(()=>{
            trashBin.destroy()
        }, 2)
    }

    /** 
     * @zh
     * 防止主角移动到屏幕外。
    */
    update(deltaTime: number) {
        this.limitPlayer()

    }
}


